home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / tools / allocrj.com / ALLOC.PAS next >
Encoding:
Pascal/Delphi Source File  |  1989-04-09  |  11.9 KB  |  380 lines

  1. {**************************************************************************
  2.   Some of the DOS memory routines presented in ALLOC.PAS and demonstrated
  3.   in ALLOCDEM.PAS, were initially uploaded by Richard Sadowsky as DOSMEM
  4.   (version 1.1), and released to the public domain on 8/22/88.  That
  5.   unit was especially appreciated by those of us who code in both
  6.   Turbo Pascal and Turbo C.  30-40% of the code in the ALLOC unit was
  7.   taken from DOSMEM.
  8.  
  9.   However, DOSMEM had its DOS routines written in assembly language,
  10.   and required use as external *.obj files.  Since I frequently forget
  11.   *.obj files when I'm working at differenct locations, and more importantly,
  12.   since I'm not good at assembly, I re-wrote the routines using interrupts,
  13.   calling the new unit ALLOC.PAS, in deference to Turbo C's <alloc.h>.  In
  14.   addition, a few other modifications were made to the error-handling routine,
  15.   as well as making the interrupt routines internal to the unit, re-naming
  16.   a few things, and adding calloc, which has as its argument, the desired
  17.   fillpattern with which to clear the RAM block (unlike C's calloc).
  18.  
  19.   modification history:
  20.     1. v1.1 adapted from MEMDOS 1.1 changing assembly to MsDos calls.
  21.     2. v1.2 reorganized unit, changed error handling.
  22.     3. v1.3 added calloc, expanded demo.
  23.     4. v1.4 :
  24.        a. the "carry" register flag is now monitored in the internal routines
  25.             for errors, rather than examing AX for values 7-9.
  26.        b. returns a variable pointer (re-set to NIL) in the free() and
  27.             farfree() procedures.
  28.        c. prevents freeing a previously freed pointer and reallocating
  29.             a pointer assiged to NIL, and encourages initialization of
  30.             memory pointers to NIL prior to use in order to avoid
  31.             unpredictable results from DOS (see demo).
  32.        d. corrected a bug in initvideo() which should use Mem[], not MemW[].
  33.        e. MallocError renamed to AllocError.
  34.        f. expanded comments.
  35.  
  36.   Robert L. Jones,  CIS [71251,2566]
  37.  
  38.   Version 1.4 released to the public domain 4/9/89.
  39.  
  40.  
  41.   ---------------------------------------------------------------------------
  42.   A comment on ALLOC and TP's heap:
  43.  
  44.   The ALLOC unit cannot be used without some planning.  In order to access
  45.   DOS using Int 21, the memory compiler option for Turbo Pascal needs to be
  46.   used to provide sufficient memory for DOS to allocate RAM.  That is, without
  47.   an upper limit on the heap size, Turbo Pascal will assign any extra RAM,
  48.   which it doesn't use, to the heap.  If all of the available RAM is thus
  49.   assigned to the heap, then no RAM will be accessible to the ALLOC routines
  50.   (i.e., for use by DOS).  This does not mean that a portion cannot be
  51.   retained for use on the heap, rather it implies that enough RAM must be
  52.   available for DOS if you want to allocate some of it using ALLOC.
  53.  
  54.   For example, see the memory compiler option at the start of the demo:
  55.  
  56.     $M 1024,0,0  <- the last digit sets the maximum value assigned for
  57.                     the heap.  this value could have easily been 10000,
  58.                     but then 10000 bytes less would be available for ALLOC.
  59.  
  60. ***************************************************************************}
  61.  
  62. unit ALLOC;
  63.  
  64. interface
  65.  
  66. uses Dos;
  67.  
  68. const
  69.   { the array is set at 7-9 due to the 3 possible errors returned in AX }
  70.   MemError : array [7..9] of string[40] =
  71.              ('Memory Control Blocks Destroyed',
  72.               'Insufficient Memory','Invalid Segment Specified');
  73. var
  74.   AllocError  : byte;
  75.  
  76. function  malloc  (SizeInBytes : word) : pointer;
  77. function  calloc  (fillpattern : byte; SizeInBytes : word) : pointer;
  78. function  realloc (p : pointer; NewSizeInBytes : word) : pointer;
  79. procedure free    (var p : pointer);
  80. procedure farfree (var p : pointer);
  81. function  coreleft : word;
  82. function  farmalloc  (SizeInBytes : longint) : pointer;
  83. function  farcalloc  (fillpattern : byte; SizeInBytes : longint) : pointer;
  84. function  farrealloc (p : pointer; NewSizeInBytes : longint) : pointer;
  85. function  farcoreleft : longint;
  86.  
  87.  
  88. implementation
  89.  
  90. {**************************************************************************
  91.   Internal routines for allocating RAM.  DOS Intr 21h is called.
  92.  
  93.   If the request allocation, reallocation, or freeing is successful,
  94.   AllocError is set to 0. If an error occurs [insufficient memory (8),
  95.   control block damage (7), or invalid segment (9)], AllocError is
  96.   set accordingly.  The error is indicated by the Carry Flag record of
  97.   the register, which is determined by AND'ing with the Turbo Pascal
  98.   constant FCarry.  If the Carry Flag is clear then everything is OK, and
  99.   0 is returned.  If the Carry Flag is not clear, then AX contains the
  100.   error code (7, 8, or 9), and this value is returned instead of 0.
  101. ***************************************************************************}
  102.  
  103. type
  104.   PtrPtr       = ^pointer;
  105. var
  106.   regs : registers;
  107.  
  108.  
  109. function DosAlloc (SizeInParas : word;
  110.                    var Largest : word;
  111.                    var Segment : word) : integer;
  112. {
  113.   low level dos memory allocation function.  This function
  114.   calls DOS function 48h to allocate the specified number
  115.   of paragraphs.  The maximum number of free paragraphs is
  116.   returned in BX if the number of paragraphs requested is
  117.   greater than the amount of memory free.  Only the segment
  118.   of the allocated memory is returned (because the offset is
  119.   always 0).
  120. }
  121. begin
  122.   with regs do begin
  123.     ah := $48;
  124.     bx := SizeInParas;
  125.     MSDOS(regs);
  126.     if (flags AND FCarry = 0) then begin
  127.       { request was successful }
  128.       Segment := ax;
  129.       Largest := bx;
  130.       DosAlloc := 0;
  131.     end
  132.     else begin
  133.       { if insufficient memory for requested block, return largest possible }
  134.       if (ax = $08) then
  135.         Largest := bx
  136.       else
  137.         Largest := 0;
  138.       DosAlloc := ax;
  139.     end;
  140.   end;
  141. end;
  142.  
  143.  
  144. function DosFree (Segment : word) : integer;
  145. {
  146.   low level dos memory free routine.  This function calls
  147.   DOS function 49h to free memory previously allocated with
  148.   DosAlloc (DOS function 48h).
  149. }
  150. begin
  151.   with regs do begin
  152.     ah := $49;
  153.     es := Segment;
  154.     MSDOS(regs);
  155.     if (flags AND FCarry = 0) then
  156.       { request was successful }
  157.       DosFree := 0
  158.     else
  159.       DosFree := ax;
  160.   end;
  161. end;
  162.  
  163.  
  164. function DosRealloc (NewSizeInParas : word;
  165.                      var Largest    : word;
  166.                      var Segment    : word) : integer;
  167. {
  168.   low level dos memory reallocation routine.  This function calls
  169.   DOS function 4Ah to realloc memory previously allocated with
  170.   DosAlloc (DOS function 48h).
  171. }
  172. begin
  173.   with regs do begin
  174.     ah := $4A;
  175.     bx := NewSizeInParas;
  176.     es := Segment;
  177.     MSDOS(regs);
  178.     if (flags AND FCarry = 0) then begin
  179.       { request was successful }
  180.       Segment := ax;
  181.       Largest := bx;
  182.       DosRealloc := 0;
  183.     end
  184.     else begin
  185.       { if insufficient memory for requested block, return largest possible }
  186.       if (ax = $08) then
  187.         Largest := bx
  188.       else
  189.         Largest := 0;
  190.       DosRealloc := ax;
  191.     end;
  192.   end;
  193. end;
  194.  
  195.  
  196.  
  197.  
  198. {**************************************************************************
  199.   External routines for allocating RAM.  Pointers are returned as NIL if
  200.   the memory request was unsuccessful (AllocError <> 0).
  201. ***************************************************************************}
  202.  
  203. function malloc (SizeInBytes : word) : pointer;
  204. var
  205.   L,Segment,SizeInP : word;
  206. begin
  207.   { divide size in bytes by 16 to get paragraphs }
  208.   SizeInP := SizeInBytes SHR 4;
  209.   { if size in bytes not evenly รท by 16, add 1 }
  210.   if SizeInBytes MOD 16 <> 0 then inc(SizeInP);
  211.   { try to allocate memory }
  212.   AllocError := DosAlloc(SizeInP,L,Segment);
  213.   if (AllocError = 0) then
  214.     {return ptr to allocated memory }
  215.     malloc := ptr(Segment,0)
  216.   else
  217.     malloc := NIL;
  218. end;
  219.  
  220.  
  221. function calloc (fillpattern : byte; SizeInBytes : word) : pointer;
  222. var
  223.   L,Segment,SizeInP,i : word;
  224.   p : pointer;
  225. begin
  226.   SizeInP := Word(SizeInBytes SHR 4);
  227.   if SizeInBytes MOD 16 <> 0 then inc(SizeInP);
  228.   AllocError := DosAlloc(SizeInP,L,Segment);
  229.   if (AllocError = 0) then begin
  230.     p := ptr(Segment,0);
  231.     calloc := p;
  232.     fillchar(p^, SizeInBytes, fillpattern);
  233.     end
  234.   else
  235.     calloc := NIL;
  236. end;
  237.  
  238.  
  239. function realloc (p : pointer; NewSizeInBytes : word) : pointer;
  240. var
  241.   L,Segment,SizeInP : word;
  242. begin
  243.   { prevent reallocating a pointer not assigned by malloc()/calloc() }
  244.   if (p = NIL) then begin
  245.     AllocError := $09;
  246.     realloc := NIL;
  247.     exit;
  248.     end;
  249.   SizeInP := NewSizeInBytes SHR 4;
  250.   if NewSizeInBytes MOD 16 <> 0 then inc(SizeInP);
  251.   Segment := Seg(PtrPtr(p)^);
  252.   AllocError := DosRealloc(SizeInP,L,Segment);
  253.   if (AllocError = 0) then
  254.     realloc := ptr(Segment,0)
  255.   else
  256.     realloc := NIL;
  257. end;
  258.  
  259.  
  260. procedure free (var p : pointer);
  261. begin
  262.   { return error if unable to free memory; reset p to NIL. }
  263.   { in addition, a check is done to avoid "freeing" an already freed pointer }
  264.   if (p = NIL) then begin
  265.     AllocError := $09;
  266.     exit;
  267.     end;
  268.   AllocError := DosFree(Seg(PtrPtr(p)^));
  269.   p := NIL;
  270. end;
  271.  
  272.  
  273. function coreleft : word;
  274. var
  275.   Largest, Segment : word;
  276.   Err              : byte;
  277. begin
  278.   { since you can't allocate FFFFh paragraphs on a 640K machine, this }
  279.   { request will always generate an error, and return the largest free }
  280.   { blocks currently available }
  281.   Err := DosAlloc($FFFF, Largest, Segment);
  282.   coreleft := Largest;
  283. end;
  284.  
  285.  
  286.  
  287.  
  288. {*****************************************************************************
  289.   FAR memory routines for allocating large blocks of RAM
  290.       (up to all of free ram)
  291.  
  292.   These routine are the same as above, except LONGINTs are used to represent
  293.   the memory size in bytes, not paragraphs.  With LONGINTs, up to all of free
  294.   memory can be allocated with a single call (and therefore, a contiguous
  295.   block of memory).
  296. ******************************************************************************}
  297.  
  298. function farmalloc (SizeInBytes : longint) : pointer;
  299. var
  300.   L,Segment,SizeInP : word;
  301. begin
  302.   SizeInP := Word(SizeInBytes SHR 4);
  303.   if SizeInBytes MOD 16 <> 0 then inc(SizeInP);
  304.   AllocError := DosAlloc(SizeInP,L,Segment);
  305.   if (AllocError = 0) then
  306.     farmalloc := ptr(Segment,0)
  307.   else
  308.     farmalloc := NIL;
  309. end;
  310.  
  311.  
  312. function farcalloc (fillpattern : byte; SizeInBytes : longint) : pointer;
  313. var
  314.   L,Segment,SizeInP : word;
  315.   p : pointer;
  316. begin
  317.   SizeInP := Word(SizeInBytes SHR 4);
  318.   if SizeInBytes MOD 16 <> 0 then inc(SizeInP);
  319.   AllocError := DosAlloc(SizeInP,L,Segment);
  320.   if (AllocError = 0) then begin
  321.     p := ptr(Segment,0);
  322.     farcalloc := p;
  323.     fillchar(p^, SizeInBytes, fillpattern);
  324.     end
  325.   else
  326.     farcalloc := NIL;
  327. end;
  328.  
  329.  
  330. function farrealloc (p : pointer; NewSizeInBytes : longint) : pointer;
  331. var
  332.   L,Segment,SizeInP : word;
  333. begin
  334.   { prevent farreallocating a pointer not assigned by farmalloc()/farcalloc() }
  335.   if (p = NIL) then begin
  336.     AllocError := $09;
  337.     farrealloc := NIL;
  338.     exit;
  339.     end;
  340.   SizeInP := Word(NewSizeInBytes SHR 4);
  341.   if NewSizeInBytes MOD 16 <> 0 then inc(SizeInP);
  342.   Segment := Seg(PtrPtr(p)^);
  343.   AllocError := DosRealloc(SizeInP,L,Segment);
  344.   if (AllocError = 0) then
  345.     farrealloc := ptr(Segment,0)
  346.   else
  347.     farrealloc := NIL;
  348. end;
  349.  
  350.  
  351. function farcoreleft : longint;
  352. var
  353.   Largest, Segment : word;
  354.   Err              : byte;
  355. begin
  356.   Err := DosAlloc($FFFF, Largest, Segment);
  357.   farcoreleft := longint (Largest) SHL 4;
  358. end;
  359.  
  360.  
  361. procedure farfree (var p : pointer);
  362. {
  363.   a thoroughtly unnecessary procedure, since free() does exactly the same
  364.   thing due to the fact that pointers and longints are 32-bits long.
  365.   but heh, why not maintain consistency?
  366.   as with free(), p is reset to NIL to tell the user what happened.
  367. }
  368. begin
  369.   if (p = NIL) then begin
  370.     AllocError := $09;
  371.     exit;
  372.     end;
  373.   AllocError := DosFree(Seg(PtrPtr(p)^));
  374.   p := NIL;
  375. end;
  376.  
  377.  
  378. begin
  379.   { ALLOC }
  380. end.